//编写代码, 实现阻塞队列案例
//——这里需要注意，阻塞队列的案例，而不仅仅是实现一个阻塞队列。案例如：生产者消费者模型。是对阻塞队列的应用。
import java.util.Random;

import static java.lang.Math.random;

public class Test2 {
    public static void main2(String[] args) throws InterruptedException {
        TestLOCLandTHROW t = new TestLOCLandTHROW();
        t.test1();//
        t.test2();//只是加了锁，不需要抛异常
        t.test3();//这里用到了wait,可能会被interrupt意外唤醒，需要抛出对应异常
    }

    public static void main(String[] args) {
        Object lock = new Object();


        //创建一个队列
        MyBlockingQueue myBlockingQueue = new MyBlockingQueue();
        Thread customer = new Thread(()->{
           while(true){
               try {
                   synchronized (lock){
                       Integer cust = myBlockingQueue.take();
                       if(cust == null){
                           lock.wait();
                       }
                       System.out.println("消费了:"+cust+"，当前元素个数："+myBlockingQueue.getSize());
                       lock.notify();
                   }
                   //Thread.sleep(3000);
               } catch (InterruptedException e) {
                   //throw new RuntimeException(e);
                   e.printStackTrace();
               }
               /*try {

                       int cust = myBlockingQueue.take();
                       System.out.println("消费了:"+cust+"，当前元素个数："+myBlockingQueue.getSize());

                   //Thread.sleep(3000);
               } catch (InterruptedException e) {
                   //throw new RuntimeException(e);
                   e.printStackTrace();
               }*/
           }

        },"customer");
        customer.start();
        Thread producer = new Thread(()->{
            Random random = new Random();
            while(true){
                int product = random.nextInt(100);
                try {
                    synchronized (lock){
                        myBlockingQueue.put(product);
                        System.out.println("产生了："+product+"，当前元素个数："+myBlockingQueue.getSize());
                        lock.notify();
                    }
                    //Thread.sleep(3000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                /*try {

                        myBlockingQueue.put(product);
                        System.out.println("产生了："+product+"，当前元素个数："+myBlockingQueue.getSize());

                    //Thread.sleep(3000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }*/

            }
        },"producer");
        producer.start();
    }
}

class MyBlockingQueue{
    Object lock = new Object();
    int[] strs = new int[1000];
    int size = 0;//有效元素个数
    int len = strs.length;
    int head = 0;
    int tail = 0;//tail指向的位置，应该是能放、要放元素的位置

    void put(int num) throws InterruptedException {
        synchronized (lock){
            while(size>=len){
                //队列满了
                //需要让这个代码能够实现阻塞:
                lock.wait();
            }
            strs[tail] = num;//放新元素
            tail++;
            if(tail>=len){
                tail = tail%len;
            }
            size++;

            lock.notify();
        }
    }

    int take() throws InterruptedException {
        Integer n = null;
        synchronized (lock){
            while(size<=0){
                lock.wait();
            }

            n = strs[head];
            head ++;
            if(head>=len){
                head = 0;
            }
            size--;
            lock.notify();
        }
        return n;
    }

    int getSize(){
        return size;
    }
}

class TestLOCLandTHROW{
    static int size = 0;
    public static void test1(){
        synchronized(TestLOCLandTHROW.class){
            System.out.println("加锁的方法，test1()");
        }
    }
    public static void test2(){
        System.out.println("不加锁的方法，test2()");
    }
    public static void test3() throws InterruptedException {
        Object lock = new Object();
        synchronized(lock){
            if(size == 0)
            lock.wait();
        }
    }

}
